// Tencent is pleased to support the open source community by making
// 蓝鲸智云 - 监控平台/日志平台 (BlueKing - Monitor/Log) available.
// Copyright (C) 2017-2022 THL A29 Limited, a Tencent company. All rights reserved.
// Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://opensource.org/licenses/MIT
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//

package receiver

import (
	"github.com/TencentBlueKing/bkmonitor-kits/logger"

	"github.com/TencentBlueKing/bk-collector/confengine"
	"github.com/TencentBlueKing/bk-collector/define"
)

func parseApmConfig(conf *confengine.Config) (define.ApmConfig, error) {
	var apmConf define.ApmConfig
	if err := conf.UnpackChild(define.ConfigFieldApmConfig, &apmConf); err != nil {
		return apmConf, err
	}

	logger.Infof("apmconf: %+v", apmConf)
	return apmConf, nil
}

func NewOneApmCacheHolder(conf *confengine.Config) (CacheHolder, error) {
	apmConf, err := parseApmConfig(conf)
	if err != nil {
		return nil, err
	}

	switch apmConf.OneApm.ConfigMode {
	default:
		return newOneApmMemCacheHolder(conf, apmConf)
	}
}

type memCacheHolderParser struct{}

func newOneApmMemCacheHolder(conf *confengine.Config, apmConf define.ApmConfig) (CacheHolder, error) {
	return memCacheHolderParser{}.Parse(conf, apmConf)
}

func (p memCacheHolderParser) parseOneApmSubConfigs(configs []*confengine.Config, ch CacheHolder) []OneApmInstanceIDConfig {
	instances := make([]OneApmInstanceIDConfig, 0)
	for _, c := range configs {
		var subConf OneApmSubConfig
		if err := c.Unpack(&subConf); err != nil {
			logger.Errorf("failed to unpack config, err: %v", err)
			continue
		}
		if subConf.Type != define.ConfigTypeSubConfig {
			continue
		}
		if subConf.Token == "" {
			logger.Warnf("ignore empty token in subconfig: %+v", subConf)
			continue
		}

		logger.Infof("subconfig token: %s", subConf.Token)
		if subConf.Default != nil {
			logger.Infof("%s oneapm config: %+v", define.SubConfigFieldDefault, *subConf.Default)
			id := Identifier{
				Token: subConf.Token,
				Type:  define.SubConfigFieldDefault,
			}
			if err := ch.SetConfig(id, subConf.Default.Bytes()); err != nil {
				logger.Errorf("failed to set default config: %v", err)
			}
		}

		for _, srv := range subConf.Service {
			logger.Infof("%s oneapm config[%s]: %+v", define.SubConfigFieldService, srv.ID, srv.OneApm)
			id := Identifier{
				Token:  subConf.Token,
				Type:   define.SubConfigFieldService,
				TypeId: srv.ID,
			}
			if err := ch.SetConfig(id, srv.OneApm.Bytes()); err != nil {
				logger.Errorf("failed to set service config: %v", err)
			}
		}

		for _, inst := range subConf.Instance {
			logger.Infof("%s oneapm config[%s]: %+v", define.SubConfigFieldInstance, inst.ID, inst.OneApm)
			id := Identifier{
				Token:  subConf.Token,
				Type:   define.SubConfigFieldInstance,
				TypeId: inst.ID,
			}

			if err := ch.SetConfig(id, inst.OneApm.Bytes()); err != nil {
				logger.Errorf("failed to set instance config: %v", err)
			}
		}
	}
	return instances
}

// parseOneApmConfig 解析 OneApm 配置
func (p memCacheHolderParser) parseOneApmConfig(typ string, conf *confengine.Config) (*OneApmInstanceConfig, error) {
	var oneApmConf OneApmInstanceConfig
	if err := conf.UnpackChild(define.ConfigFieldOneApm, &oneApmConf); err != nil {
		return nil, err
	}
	logger.Infof("%s oneapm config: %+v", typ, oneApmConf)
	return &oneApmConf, nil
}

// Parse 解析 oneapm 配置并生成内存 confengine.CacheHolder
func (p memCacheHolderParser) Parse(conf *confengine.Config, apmConf define.ApmConfig) (CacheHolder, error) {
	ch, _ := NewMemCacheHolder()
	if oneApmConf, err := p.parseOneApmConfig("main", conf); err == nil {
		if err := ch.SetGlobal(oneApmConf.Bytes()); err != nil {
			logger.Errorf("failed to set default config: %v", err)
		}
	}

	// 加载所有子配置
	subConfigs := confengine.LoadConfigPatterns(apmConf.Patterns)
	p.parseOneApmSubConfigs(subConfigs, ch)

	platformConfig := confengine.LoadPlatformConfigs(apmConf.Patterns)
	if platformConfig != nil && platformConfig.Has(define.ConfigFieldOneApm) {
		if oneApmConf, err := p.parseOneApmConfig("platform", conf); err == nil {
			if err := ch.SetGlobal(oneApmConf.Bytes()); err != nil {
				logger.Errorf("failed to set default config: %v", err)
			}
		}
	}

	return ch, nil
}
